package model.datasource;

import java.io.IOException;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jolbox.bonecp.BoneCP;
import com.jolbox.bonecp.BoneCPConfig;

import common.Constants;

public class DatabaseManager
{
	private static Logger logger = LoggerFactory.getLogger(DatabaseManager.class);
	
	private boolean initialized = false;
	private static DatabaseManager instance;
	private BoneCP connectionPool;
	private BoneCPConfig connectionConfig;
	
	private String driverClass = null;
	private String jdbcUrl = null;
	private String userName = null;
	private String password = null;
	private String filename = null;

	private int idleConnectionTestPeriod = 60;
	private int idleMaxAge = 240;
	private int maxConnectionsPerPartition = 30;
	private int minConnectionsPerPartition = 10;
	private int partitionCount = 3;
	private int acquireIncrement = 5;
	private int statementsCacheSize = 100;
	private int releaseHelperThreads = 3;
	
	protected DatabaseManager()
	{
	}
	
	public int initialize()
	{
		if( initialized )
		{
			return Constants.DATABASE_INITIALIZED;
		}
		else
		{
			try
			{
				Properties props = new Properties();
				
				props.load(ClassLoader.getSystemResourceAsStream("config.properties"));
				
				if(props.getProperty("database") != null)
				{								
					this.jdbcUrl = props.getProperty("jdbcUrl");
					this.driverClass = props.getProperty("driverClass");
					this.userName = props.getProperty("username");
					this.password = props.getProperty("password");
					this.filename = props.getProperty("database");
					
					logger.info("databse is used " + this.filename);
					
					Class.forName(this.driverClass);
					
					connectionConfig = new BoneCPConfig();
					if(this.jdbcUrl.toLowerCase().contains("sqlite"))
					{
						this.jdbcUrl += Paths.get(System.getProperty("user.home"), Constants.PROJECT, this.filename).toString() + ".db";						
						logger.debug(this.jdbcUrl);
					}
					connectionConfig.setJdbcUrl(this.jdbcUrl);
					connectionConfig.setUsername(this.userName);
					connectionConfig.setPassword(this.password);
					
					connectionConfig.setMinConnectionsPerPartition(this.minConnectionsPerPartition);
					connectionConfig.setMaxConnectionsPerPartition(this.maxConnectionsPerPartition);
					connectionConfig.setIdleConnectionTestPeriodInMinutes(this.idleConnectionTestPeriod);
					connectionConfig.setIdleMaxAgeInMinutes(this.idleMaxAge);
					connectionConfig.setPartitionCount(this.partitionCount);
					
					connectionPool = new BoneCP(connectionConfig);
					
					initialized = true;			
					return Constants.OK;
				}
			}
			catch(IOException e)
			{
				e.printStackTrace();
			}
			catch(ClassNotFoundException e)
			{
				e.printStackTrace();
			}
			catch( SQLException e )
			{
				e.printStackTrace();
			}
			return Constants.CONNECTION_POOL_INIT_ERROR;
		}
	}
	
	public void uninitialize()
	{
		this.connectionPool.shutdown();
		initialized = false;
	}
	
	public static DatabaseManager getInstance()
	{
		if( instance == null )
		{
			instance = new DatabaseManager();
		}
		return instance;
	}
	
	public Connection getConnection() throws SQLException
	{
		assert(initialized);
		return connectionPool.getConnection();
	}
	
}
